//
//  Location.swift
//  Social
//
//  Created by 李响 on 2018/3/22.
//  Copyright © 2018年 LiveTrivia. All rights reserved.
//

import Foundation
import CoreLocation
import UIKit

class Location: NSObject {
    
    static let shared = Location()
    
    typealias Completion = (Swift.Result<Result, Error>) -> Void
    private var completion: Completion?
    private let manager = CLLocationManager()
    
    override init() {
        super.init()
        
        manager.delegate = self
        manager.desiredAccuracy = kCLLocationAccuracyHundredMeters
        manager.distanceFilter = kCLDistanceFilterNone
    }
}

extension Location {
    
    static var isEnabled: Bool {
        let services = CLLocationManager.locationServicesEnabled()
        switch CLLocationManager.authorizationStatus() {
        case .authorizedWhenInUse,
             .authorizedAlways where services == true:
            return true
        default:
            return false
        }
    }
    
    func get(completion: @escaping Completion) {
        guard CLLocationManager.locationServicesEnabled() else {
            completion(.failure(.services))
            return
        }
        self.completion = completion
        
        switch CLLocationManager.authorizationStatus() {
        case .authorizedWhenInUse, .authorizedAlways:
            manager.startUpdatingLocation()
            
        case .denied, .restricted:
            completion(.failure(.permissions))
            self.completion = nil
            
        default:
            manager.requestWhenInUseAuthorization()
        }
    }
    
    static func reverseGeocode(_ latitude: Double, _ longitude: Double, locale: Locale = Locale(identifier: "zh-Hans-CN"), completion: @escaping Completion) {
        reverseGeocode(
            .init(latitude: latitude, longitude: longitude),
            locale: locale,
            completion: completion
        )
    }
    
    static func reverseGeocode(_ location: CLLocation, locale: Locale = Locale(identifier: "zh-Hans-CN"), completion: @escaping Completion) {
        
        func finished(_ placemarks: [CLPlacemark]?, _ error: Swift.Error?) {
            guard
                let placemark = placemarks?.first,
                let city = placemark.locality,
                let area = placemark.subLocality else {
                completion(.failure(.failure(error)))
                return
            }
            let result = Result(
                country: placemark.country ?? "",
                province: placemark.administrativeArea ?? city,
                city: city,
                area: area,
                longitude: location.coordinate.longitude,
                latitude: location.coordinate.latitude
            )
            completion(.success(result))
        }
        
        let coder = CLGeocoder()
        
        if #available(iOS 11.0, *) {
            coder.reverseGeocodeLocation(location, preferredLocale: locale) { (placemarks, error) in
                finished(placemarks, error)
            }

        } else {
            // 强制更换中文语言
            let languagesKey = "AppleLanguages"
            let languages = UserDefaults.standard.array(forKey: languagesKey)
            UserDefaults.standard.set([locale.identifier], forKey: languagesKey)
            
            coder.reverseGeocodeLocation(location) { (placemarks, error) in
                // 恢复语言
                UserDefaults.standard.set(languages, forKey: languagesKey)
                finished(placemarks, error)
            }
        }
    }
}

extension Location: CLLocationManagerDelegate {
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        
        switch status {
        case .denied, .restricted:
            completion?(.failure(.permissions))
            completion = nil
            
        default:
            manager.startUpdatingLocation()
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.first else { return }
        
        manager.stopUpdatingLocation()
        
        guard let completion = self.completion else { return }
        self.completion = nil
        
        Location.reverseGeocode(location) { (result) in
            completion(result)
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Swift.Error) {
        completion?(.failure(.failure(error)))
        completion = nil
    }
}

extension Location {
    
    struct Result {
        let country: String         //国家
        let province: String        //省
        let city: String            //市
        let area: String            //区
        let longitude: Double
        let latitude: Double
    }
    
    enum Error: Swift.Error {
        case services                   //定位服务
        case permissions                //定位权限
        case failure(Swift.Error?)      //定位失败
        
        var localizedDescription: String {
            switch self {
            case .services:             return "未开启定位服务"
            case .permissions:          return "无法获取定位权限"
            case .failure(let error):   return error?.localizedDescription ?? ""
            }
        }
    }
}
